#include "stamp_classifier.h"

#include <math.h>

#include <fstream>
#include <iostream>
#include <vector>
using namespace std;

void stamp_classifier::train(boosting_problem & prob, int argc, char ** argv) {
	int l = prob.l;

	vector<double> p_sum;
	vector<double> n_sum;
	int p = 0;
	int n = 0;
	p_sum.resize(prob.dim);
	n_sum.resize(prob.dim);

	for(int i = 0; i < l; i++) {
		int y = (int) prob.y[i];
		boosting_node * x = prob.x[i];
		
		vector<double> & sum = y == 1 ? p_sum : n_sum;
		if(y == 1) {
			p++;
		} else {
			n++;
		}

		while(x->index != -1) {
			sum[x->index - 1] += x->value;
			x++;
		}
	}

	// normalize
	for(int i = 0; i < prob.dim; i++) {
		p_sum[i] /= p;
		n_sum[i] /= n;
	}

	double max_distance = 0;
	int best_dim = -1;
	for(int i = 0; i < prob.dim; i++) {
		double distance = abs(p_sum[i] - n_sum[i]);
		if(distance > max_distance) {
			max_distance = distance;
			best_dim = i;
		}
	}

	dim = best_dim + 1;
	threshold = (p_sum[best_dim] + n_sum[best_dim]) * 0.5;
	direction = p_sum[best_dim] > n_sum[best_dim] ? 1 : -1;
}

double stamp_classifier::test(boosting_node * x) {
	double value = 0;
	while(x->index != -1) {
		if(x->index == dim) {
			value = x->value;
			break;
		}
		x++;
	}

	double distance = value - threshold;
	double f = direction * distance;
	double sigmoid = 1 / (1 + exp(-f));
	return sigmoid;
}

void stamp_classifier::load(string filename) {
	ifstream fin(filename.c_str());
	if(fin.fail()) {
		cout << "cannot open " << filename << endl;
	}

	fin >> dim >> threshold >> direction;
	fin.close();
}

void stamp_classifier::dump(string filename) {
	ofstream fout(filename.c_str());
	fout << dim << "\t" << threshold << "\t" << direction << endl;
	fout.close();
}
